namespace Org.Loon.Framework.Xna.Game.Action.Sprite
{
    using System.Collections.Generic;
    using Org.Loon.Framework.Xna.Game.Core;
    using Org.Loon.Framework.Xna.Game.Core.Graphics.OpenGL;
    using Org.Loon.Framework.Xna.Game.Action.Map;
    using Org.Loon.Framework.Xna.Game.Utils;
    using Org.Loon.Framework.Xna.Game.Core.Input;
    using Org.Loon.Framework.Xna.Game.Core.Graphics;
    using Org.Loon.Framework.Xna.Game.Core.Geom;

    public class StepSprite : LObject, ISprite
    {

        private const long serialVersionUID = 1L;

        private List<int[]> steps;

        private TouchSprite touch;

        private bool isRunning;

        public StepSprite()
            : this(true)
        {

        }

        public StepSprite(bool all)
            : this((LTexture)null, TouchSprite.BLOCK_SIZE, TouchSprite.BLOCK_SIZE,
                all)
        {

        }

        public StepSprite(string path)
            : this(path, true)
        {

        }

        public StepSprite(string path, bool all)
            : this(LTextures.LoadTexture(path), 0, 0, all)
        {

        }

        public StepSprite(int tileWidth, int tileHeight)
            : this(tileWidth, tileHeight, true)
        {

        }

        public StepSprite(int tileWidth, int tileHeight, bool all)
            : this((LTexture)null, tileWidth, tileHeight, all)
        {

        }

        public StepSprite(string path, int tileWidth, int tileHeight, bool all)
            : this(LTextures.LoadTexture(path), tileWidth, tileHeight, all)
        {

        }

        public StepSprite(LTexture tex2d, int tileWidth, int tileHeight, bool all)
            : this(null, tex2d, tileWidth, tileHeight, LSystem.screenRect.width,
                LSystem.screenRect.height, all)
        {

        }

        public StepSprite(Field2D field, LTexture tex2d, int tileWidth,
                int tileHeight, int maxWidth, int maxHeight, bool all)
        {
            this.touch = new TouchSprite(field, tex2d, tileWidth, tileHeight,
                    maxWidth, maxHeight, all);
            this.steps = new List<int[]>(10);
            this.SetDelay(20);
        }

        public TouchSprite GetTouchSprite()
        {
            return touch;
        }

        public long GetDelay()
        {
            return touch.GetDelay();
        }

        public void SetDelay(long d)
        {
            touch.SetDelay(d);
        }

        public void Go()
        {
            this.isRunning = true;
        }

        public void Stop()
        {
            this.isRunning = false;
        }

        public bool IsComplete()
        {
            return this.isRunning;
        }

        public void AddEnd(int x, int y)
        {
            lock (steps)
            {
                steps.Insert(steps.Count, new int[] { x, y });
            }
        }

        public void Add(int x, int y)
        {
            lock (steps)
            {
                CollectionUtils.Add(steps, new int[] { x, y });
            }
        }

        public void AddBegin(int x, int y)
        {
            lock (steps)
            {
                steps.Insert(0, new int[] { x, y });
            }
        }

        public int Size()
        {
            lock (steps)
            {
                return steps.Count;
            }
        }

        public int GetX(int i)
        {
            lock (steps)
            {
                if (steps.Count == 0)
                {
                    return 0;
                }
                return ((int[])steps[i])[0];
            }
        }

        public int GetY(int i)
        {
            lock (steps)
            {
                if (steps.Count == 0)
                {
                    return 0;
                }
                return ((int[])steps[i])[1];
            }
        }

        public int[] Remove(int i)
        {
            lock (steps)
            {
                return (int[])CollectionUtils.RemoveAt(steps, i);
            }
        }

        public void RemoveAll()
        {
            lock (steps)
            {
                CollectionUtils.Clear(steps);
            }
        }

        public void OnPosition(LTouch t)
        {
            touch.OnPosition(t);
        }

        public void OnPosition(float x, float y)
        {
            touch.OnPosition(x, y);
        }

        public override int GetHeight()
        {
            return touch.GetHeight();
        }

        public override int GetWidth()
        {
            return touch.GetWidth();
        }

        public override int GetHashCode()
        {
            int hashCode = 1;
            hashCode = LSystem.Unite(hashCode, touch.GetHashCode());
            hashCode = LSystem.Unite(hashCode, steps.Count);
            return hashCode;
        }

        public void SetTexture(string path)
        {
            touch.SetTexture(LTextures.LoadTexture(path));
        }

        public void SetTexture(LTexture tex2d)
        {
            touch.SetTexture(tex2d);
        }

        public Field2D GetField2D()
        {
            return touch.GetField2D();
        }

        private void Update()
        {
            if (isRunning)
            {
                if (steps.Count > 0)
                {
                    int[] pos = steps[0];
                    if (pos[0] < 0 || pos[1] < 0 || pos[0] > touch.GetReaderWidth()
                            || pos[1] > touch.GetReaderHeight())
                    {
                        touch.OnPosition(pos[0], pos[1]);
                    }
                    else
                    {
                        touch.OnTouch(pos[0], pos[1]);
                    }
                    CollectionUtils.RemoveAt(steps, 0);
                }
            }
        }

        public void SetFilterColor(LColor f)
        {
            touch.SetFilterColor(f);
        }

        public LColor GetFilterColor()
        {
            return touch.GetFilterColor();
        }

        public ISprite GetBindSprite()
        {
            return touch.GetBindSprite();
        }

        public void Bind(ISprite sprite)
        {
            touch.Bind(sprite);
        }

        public override void Update(long elapsedTime)
        {
            if (!touch.IsVisible())
            {
                return;
            }
            if (touch.IsComplete())
            {
                Update();
            }
            touch.Update(elapsedTime);
        }

        public virtual void CreateUI(GLEx g)
        {
            touch.CreateUI(g);
        }

        public override float GetAlpha()
        {
            return touch.GetAlpha();
        }

        public virtual LTexture GetBitmap()
        {
            return touch.GetBitmap();
        }

        public virtual RectBox GetCollisionBox()
        {
            return touch.GetCollisionBox();
        }

        public virtual bool IsVisible()
        {
            return touch.IsVisible();
        }

        public virtual void SetVisible(bool v)
        {
            touch.SetVisible(v);
        }

        public virtual void Dispose()
        {
            this.isRunning = false;
            if (touch != null)
            {
                touch.Dispose();
                touch = null;
            }
            if (steps != null)
            {
                CollectionUtils.Clear(steps);
            }
        }
    }
}
